package com.liting.uitest.imgutils;

import com.liting.uitest.model.ImagePixel;
import com.liting.uitest.model.LabColor;


/**
 * 色差
 */
public class ColorDistance {
    private static final double K_L = 1;
    private static final double K_C = 1;
    private static final double K_H = 1;

    // 计算ΔE₀₀
    public static double calculateColorDifference(LabColor lab1, LabColor lab2) {
        // Step 1: 计算经归一化和偏移后的L*, a*, b*
        double C1 = Math.sqrt(lab1.a * lab1.a + lab1.b * lab1.b);
        double C2 = Math.sqrt(lab2.a * lab2.a + lab2.b * lab2.b);
        double C_average = (C1 + C2) / 2.0;
        double G = 0.5 * (1 - Math.sqrt(Math.pow(C_average, 7) / (Math.pow(C_average, 7) + Math.pow(25, 7))));

        double a1_prime = lab1.a * (1 + G);
        double a2_prime = lab2.a * (1 + G);
        double C1_prime = Math.sqrt(a1_prime * a1_prime + lab1.b * lab1.b);
        double C2_prime = Math.sqrt(a2_prime * a2_prime + lab2.b * lab2.b);
        double C_prime_average = (C1_prime + C2_prime) / 2.0;

        double h1_prime, h2_prime;
        if (lab1.b == 0 && lab1.a == 0) {
            h1_prime = 0;
        } else {
            h1_prime = Math.atan2(lab1.b, lab1.a) * 180 / Math.PI;
        }
        if (lab2.b == 0 && lab2.a == 0) {
            h2_prime = 0;
        } else {
            h2_prime = Math.atan2(lab2.b, lab2.a) * 180 / Math.PI;
        }
        double h_prime_average = calculateAverageHue(h1_prime, h2_prime);

        // Step 2: 计算hue difference
        double deltaH_prime = Math.abs(h2_prime - h1_prime);
        if (deltaH_prime > 180) {
            deltaH_prime = 360 - deltaH_prime;
        }

        // Step 3: 其他中间变量计算
        double T = 1 - 0.17 * Math.cos(Math.toRadians(h_prime_average - 30)) +
                0.24 * Math.cos(Math.toRadians(2 * h_prime_average)) +
                0.32 * Math.cos(Math.toRadians(3 * h_prime_average + 6)) -
                0.20 * Math.cos(Math.toRadians(4 * h_prime_average - 63));
        double deltaL_prime = lab2.L - lab1.L;
        double deltaC_prime = C2_prime - C1_prime;
        double deltaH_prime_square = deltaH_prime * deltaH_prime;

        // Step 4: 计算最终的ΔE₀₀
        double SL = 1 + ((0.015 * Math.pow(lab1.L - 50, 2)) / Math.sqrt(20 + Math.pow(lab1.L - 50, 2)));
        double SC = 1 + 0.045 * C_prime_average;
        double SH = 1 + 0.015 * C_prime_average * T;
//        double deltaE = Math.sqrt(Math.pow(deltaL_prime / (K_L * SL), 2) +
//                Math.pow(deltaC_prime / (K_C * SC), 2) +
//                Math.pow(deltaH_prime_square / (K_H * SH), 2));
        double deltaE = Math.sqrt(Math.pow((double) deltaL_prime / (K_L * SL), 2) + Math.pow((double) deltaC_prime / (K_C * SC), 2) +
                Math.pow((double) deltaH_prime / (K_H * SH), 2) + (deltaC_prime / (K_C * SC)) * (deltaH_prime / (K_H * SH)));

        return deltaE;
    }


    // 计算两个颜色之间的CIE2000色差
    public static double calculateCIE2000(LabColor lab1, LabColor lab2) {

        double L1 = lab1.L, a1 = lab1.a, b1 = lab1.b;
        double L2 = lab1.L, a2 = lab2.a, b2 = lab2.b;

        double deltaL = L2 - L1;
        double deltaA = a2 - a1;
        double deltaB = b2 - b1;
        double C1 = Math.sqrt(a1 * a1 + b1 * b1);
        double C2 = Math.sqrt(a2 * a2 + b2 * b2);
        double deltaC = C2 - C1;

        // 假设的色差计算（实际上并不是真正的CIE2000公式）
        double deltaE = Math.sqrt(Math.pow(deltaL, 2) + Math.pow(deltaA, 2) + Math.pow(deltaB, 2));

        return deltaE;
    }

    // 辅助函数：计算色调差


    /**
     * CIE DE 2000
     */
    public static double CIE_2000(LabColor lab1, LabColor lab2) {
        double L1 = lab1.L, a1 = lab1.a, b1 = lab1.b;
        double L2 = lab1.L, a2 = lab2.a, b2 = lab2.b;
        double C1 = Math.sqrt(a1 * a1 + b1 * b1);
        double C2 = Math.sqrt(a2 * a2 + b2 * b2);

        //计算a' C' h'
        double L_1 = L1;
        double C_avg = (double) (C1 + C2) / 2;
        double G = 0.5 * (1 - Math.sqrt((double) (Math.pow(C_avg, 7)) / (Math.pow(C_avg, 7) + Math.pow(25, 7))));
        double a_1 = (1 + G) * a1;
        double b_1 = b1;
        double C_ab1 = Math.sqrt(Math.pow(a_1, 2) + Math.pow(b_1, 2));
        double h_ab1 = Math.atan((double) b_1 / a_1);

        double L_2 = L2;
        double a_2 = (1 + G) * a2;
        double b_2 = b2;
        double C_ab2 = Math.sqrt(Math.pow(a_2, 2) + Math.pow(b_2, 2));
        double h_ab2 = Math.atan((double) b_2 / a_2);

        //计算差值 L’ Cab’ Hab’
        double L_diff = Math.abs(L_1 - L_2);
        double C_diff = Math.abs(C_ab1 - C_ab2);
        double h_diff = Math.abs(h_ab1 - h_ab2);
        double H_diff = 2 * Math.sqrt(C_ab1 * C_ab2) * Math.sin((double) ((h_diff) / 2));

        //计算Sl Sc Sh RT RC
        double L_avg = (double) (L_1 + L_2) / 2;
        double C_ab_avg = (double) (C_ab1 + C_ab2) / 2;
        double h_ab_avg = (double) (h_ab1 + h_ab2) / 2;
        double T = 1 - 0.17 * Math.cos(h_ab_avg - 30) + 0.24 * Math.cos(2 * h_ab_avg) + 0.32 * Math.cos(3 * h_ab_avg + 6) - 0.20 * Math.cos(4 * h_ab_avg - 63);
        double S_L = 1 + ((double) (0.015 * Math.pow(L_avg - 50, 2)) / (Math.sqrt(20 + Math.pow(L_avg - 50, 2))));
        double S_C = 1 + 0.045 * C_ab_avg;
        double S_H = 1 + 0.015 * C_ab_avg * T;
        double RC = 2 * (Math.sqrt((Math.pow(C_avg, 7)) / (Math.pow(C_avg, 7) + Math.pow(25, 7))));
        double angle = 30 * Math.exp(-Math.pow((double) (h_ab_avg - 275) / (25), 2));
        double RT = -Math.sin(2 * angle) * RC;

        //选取KL KC KH，符合标准观测环境
        double K_L = 0.5;
        double K_C = 0.5;
        double K_H = 0.5;

        //色差计算
        double E = Math.sqrt(Math.pow((double) L_diff / (K_L * S_L), 2) + Math.pow((double) C_diff / (K_C * S_C), 2) +
                Math.pow((double) H_diff / (K_H * S_H), 2) + RT * (C_diff / (K_C * S_C)) * (H_diff / (K_H * S_H)));
        return E;
    }


    // 计算平均色调角度
    private static double calculateAverageHue(double h1, double h2) {
        double d = Math.abs(h1 - h2);
        if (d > 180) {
            return (h1 + h2 + 360) % 360;
        } else {
            return (h1 + h2) / 2.0;
        }
    }

}
